import sys
import time
import serial


ERROR_OPENING_PORT = '''
There was an error opening the serial port: %s

Please check the system for the correct port to use or make sure the
USB serial cable is connected.

If you want to specify the port name or number do so below, otherwise
leave the line empty and press [Enter] to quit...
'''

sleep = time.sleep
stdout = sys.stdout.write

class Caliper:
    """
    """
    def __init__(self, port='/dev/ttyUSB0'):
        """
        """
        self.stop_flag = 0
        self.caliper = self.__create_caliper(port)
        self.__reset__()

    def __reset__(self):
        self.holding_measurements = []

    def open_connection(self, port):
        """
        """
        opto_rs = {'baudrate': 4800,
                   'parity': 'E',
                   'bytesize': 7,
                   'stopbits': 2}
        try:
            caliper = serial.Serial(port, timeout=0.25, **opto_rs)
            discard_first_read = caliper.readlines(eol='\r')
        except:
            caliper = None
        return caliper

    def monitor(self, processing_fn=None):
        """
        """
        process_data = processing_fn or (lambda x: stdout('%s\n' % x[-1]))
        read_caliper = self.caliper.readline
        process_reading = self.__process_reading
        while not self.stop_flag:
            measurement = process_reading(read_caliper())
            if measurement:
                self.holding_measurements.append(measurement)
                process_data(self.holding_measurements)
            sleep(0.75)

    def __create_caliper(self, port):
        """
        """
        caliper = None
        while not caliper:
            caliper = self.open_connection(port)
            if not caliper:
                print ERROR_OPENING_PORT % port
                new_port = raw_input(' > ')
                if new_port == '':
                    return sys.exit(1)
        return caliper

    def __process_reading(self, reading, raw=False):
        """
        """
        measurement = None
        if reading:
            try:
                data = reading.strip('\r').split('\r').pop()
                measurement = float(data)
            except:
                print "Read garbage"
            if raw:
                measurement = data
        return measurement


